<template>
    <div class="container">
        <div>
            Selected regions:
            <span id="info">None</span>
        </div>
        <div id="map" class="map"></div>
        <div class="tools"></div>
    </div>
</template>

<script lang="ts" setup>
import GeoJSON from 'ol/format/GeoJSON.js';
import Map from 'ol/Map.js';
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import View from 'ol/View.js';
import { DragBox, Select } from 'ol/interaction.js';
import { Fill, Stroke, Style } from 'ol/style.js';
import { platformModifierKeyOnly } from 'ol/events/condition.js';
import TileLayer from 'ol/layer/Tile';
import { XYZ } from 'ol/source';
import { onMounted } from 'vue';

onMounted(() => {
    const vectorSource = new VectorSource({
        url: 'https://openlayers.org/data/vector/ecoregions.json',
        format: new GeoJSON()
    });

    const style = new Style({
        fill: new Fill({
            color: '#eeeeee'
        })
    });

    const map = new Map({
        target: 'map',
        view: new View({
            center: [116.397477, 39.908692],
            zoom: 12,
            projection: 'EPSG:4326'
        }),
        layers: [
            new TileLayer({
                source: new XYZ({
                    url: `http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7`
                })
            })
        ]
    });

    const selectedStyle = new Style({
        fill: new Fill({
            color: 'rgba(255, 255, 255, 0.6)'
        }),
        stroke: new Stroke({
            color: 'rgba(255, 255, 255, 0.7)',
            width: 2
        })
    });

    // a normal select interaction to handle click
    const select = new Select({
        style: selectedStyle
    });
    map.addInteraction(select);

    const selectedFeatures = select.getFeatures();

    // a DragBox interaction used to select features by drawing boxes
    const dragBox = new DragBox({
        condition: platformModifierKeyOnly
    });

    map.addInteraction(dragBox);

    dragBox.on('boxend', function () {
        const extent = dragBox.getGeometry().getExtent();
        const boxFeatures = vectorSource
            .getFeaturesInExtent(extent)
            .filter((feature) =>
                feature.getGeometry().intersectsExtent(extent)
            );

        // features that intersect the box geometry are added to the
        // collection of selected features

        // if the view is not obliquely rotated the box geometry and
        // its extent are equalivalent so intersecting features can
        // be added directly to the collection
        const rotation = map.getView().getRotation();
        const oblique = rotation % (Math.PI / 2) !== 0;

        // when the view is obliquely rotated the box extent will
        // exceed its geometry so both the box and the candidate
        // feature geometries are rotated around a common anchor
        // to confirm that, with the box geometry aligned with its
        // extent, the geometries intersect
        if (oblique) {
            const anchor = [0, 0];
            const geometry = dragBox.getGeometry().clone();
            geometry.rotate(-rotation, anchor);
            const extent = geometry.getExtent();
            boxFeatures.forEach(function (feature) {
                const geometry = feature.getGeometry().clone();
                geometry.rotate(-rotation, anchor);
                if (geometry.intersectsExtent(extent)) {
                    selectedFeatures.push(feature);
                }
            });
        } else {
            selectedFeatures.extend(boxFeatures);
        }
    });

    // clear selection when drawing a new box and when clicking on the map
    dragBox.on('boxstart', function () {
        selectedFeatures.clear();
    });

    const infoBox = document.getElementById('info');

    selectedFeatures.on(['add', 'remove'], function () {
        const names = selectedFeatures.getArray().map(function (feature) {
            return feature.get('ECO_NAME');
        });
        if (names.length > 0) {
            infoBox.innerHTML = names.join(', ');
        } else {
            infoBox.innerHTML = 'None';
        }
    });
});
</script>
<style lang="scss" setup>
.container {
    position: relative;
    width: 100%;
    height: 100%;
    .map {
        width: 90%;
        height: 90%;
    }
    .tools {
        position: absolute;
        top: 10px;
        left: 50px;
    }
}
</style>